package dialect

import (
	"fmt"
	"log"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	"code_gen/config"
	"code_gen/db"
	"code_gen/entity"
	"code_gen/logger"
)

func init() {
	RegisterDialect(DialectMysql, &MysqlDialect{})
	RegisterDialectDataTypeMapping(DialectMysql, GetJavaCommonDataTypeMapping, nil)
	RegisterDialectDataTypeMapping(DialectMysql, GetGolangCommonDataTypeMapping, nil)
}

type MysqlDialect struct {
}

func (c *MysqlDialect) ConvertDataType(ctx *Context, langType, dataType string) string {
	return GetLangDataType(DialectMysql, langType, dataType)
}
func (c *MysqlDialect) GetDB(ctx *Context, ds *config.DataSource) (*gorm.DB, error) {
	if ds.Type == "sql" {
		return nil, nil
	}
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s", ds.User, db.Decode(ds.Password), ds.Host, ds.Port, ds.DataBase, ds.Params)
	return db.CreateDB(mysql.Open(dsn))
}
func (c *MysqlDialect) GetTableInfo(ctx *Context, ds *config.DataSource, db *gorm.DB, table string) (*entity.TableInfo, error) {
	if ds.Type == "db" {
		return c.getTableInfoFromDb(ctx, ds, db, table)
	} else {
		return c.getTableInfoFromSql(ctx, ds, table)
	}
}
func (c *MysqlDialect) getTableInfoFromDb(ctx *Context, ds *config.DataSource, db *gorm.DB, tableName string) (*entity.TableInfo, error) {

	// 获取表信息
	var tableRaw map[string]interface{}
	//goland:noinspection SqlNoDataSourceInspection
	sql := fmt.Sprintf("SELECT * from information_schema.`TABLES` WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", ds.DataBase, tableName)
	logger.Log.Info("mysql get table info sql: ", sql)
	err := db.Raw(sql).Scan(&tableRaw).Error
	if err != nil {
		return nil, err
	}

	// 表注释
	tableComment := tableRaw["TABLE_COMMENT"].(string)

	// 获取表字段信息
	var rows []map[string]interface{}
	//goland:noinspection ALL
	sql = fmt.Sprintf("SELECT * from information_schema.`COLUMNS` WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'", ds.DataBase, tableName)
	logger.Log.Info("mysql get column info sql: ", sql)
	err = db.Raw(sql).Scan(&rows).Error
	if err != nil {
		log.Panic(err)
	}
	if len(rows) < 1 {
		return nil, fmt.Errorf("table %s column is illegally", tableName)
	}

	var columns []*entity.ColumnInfo
	for _, row := range rows {
		columns = append(columns, c.convertColumn(ctx, row, ds.Lang))
	}

	tableInfo := &entity.TableInfo{}
	tableInfo.Dialect = DialectMysql
	tableInfo.Lang = ds.Lang
	tableInfo.Name = tableName
	tableInfo.Comment = tableComment
	tableInfo.Columns = columns

	// 导入的包名 去重
	uniqueMap := make(map[string]bool)
	for _, column := range columns {
		dtm := GetDataTypeMapping(DialectMysql, ds.Lang, column.DataType)
		if dtm != nil && dtm.LangPackage != "" {
			uniqueMap[dtm.LangPackage] = true
		}
	}
	uniqueArray := make([]string, 0, len(uniqueMap))
	for str := range uniqueMap {
		uniqueArray = append(uniqueArray, str)
	}

	tableInfo.Packages = uniqueArray

	return tableInfo, nil
}
func (c *MysqlDialect) convertColumn(ctx *Context, dbColumn map[string]interface{}, lang string) *entity.ColumnInfo {

	ci := &entity.ColumnInfo{}
	ci.Name = dbColumn["COLUMN_NAME"].(string)
	ci.Comment = dbColumn["COLUMN_COMMENT"].(string)
	ci.DataType = dbColumn["DATA_TYPE"].(string)
	ci.PrimaryKeyFlag = dbColumn["COLUMN_KEY"].(string)
	ci.IsPrimaryKey = ci.PrimaryKeyFlag == "PRI"
	ci.LangDataType = c.ConvertDataType(ctx, lang, ci.DataType)
	ci.Raw = dbColumn

	return ci

}
func (c *MysqlDialect) getTableInfoFromSql(ctx *Context, ds *config.DataSource, sql string) (*entity.TableInfo, error) {
	return nil, nil
}
